﻿/*********************************************************************************/
/**    Sims3Pack Readme Generator                                               **/
/**    Copyright (C) 2012  Anja Knackstedt                                      **/
/**                                                                             **/
/**    This program is free software: you can redistribute it and/or modify     **/
/**    it under the terms of the GNU General Public License as published by     **/
/**    the Free Software Foundation, either version 3 of the License, or        **/
/**    (at your option) any later version.                                      **/
/**                                                                             **/
/**    This program is distributed in the hope that it will be useful,          **/
/**    but WITHOUT ANY WARRANTY; without even the implied warranty of           **/
/**    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            **/
/**    GNU General Public License for more details.                             **/
/**                                                                             **/
/**    You should have received a copy of the GNU General Public License        **/
/**    along with this program.  If not, see <http://www.gnu.org/licenses/>.    **/
/**                                                                             **/
/*********************************************************************************/




using System;
using System.Xml;
using System.Drawing;
using Sims3PackReadmeGenerator.ContentDesciption;

namespace Sims3PackReadmeGenerator.Sims3PackReader
{
    class Sims3PackReaderClass
    {

        #region events

        public delegate void NewCCDescriptionEventHandler(object sender, ContentDescriptionEventArgs e);
        public event NewCCDescriptionEventHandler OnNewCCDescriptionHandler;

        public void OnNewCCDescription(ContentDescriptionEventArgs e)
        {
            if (OnNewCCDescriptionHandler != null)
                OnNewCCDescriptionHandler(this, e);
        }

        #endregion

        #region constructor

        public Sims3PackReaderClass()
        {            
            this.ReferenceResolver = new ReferenceResolver();
        }

        #endregion

        #region properties

        public ReferenceResolver ReferenceResolver { get; set; }

        #endregion

        #region methods

        /// <summary>
        /// reads sims3pack file
        /// </summary>
        /// <param name="filePath">path of the sims3pack file</param>       
        public ContentDescription readSims3PackFile(string filePath)
        {
            int binaryStartPosition=0;
            ContentDescription description = null;
            
            string sims3PackXmlPart = Sims3PackBinaryReader.getXMLPart(filePath, out binaryStartPosition);
            if (sims3PackXmlPart != "")
            {
                description = readXML(sims3PackXmlPart, filePath, binaryStartPosition);
            }
           
            return description;
        }

        /// <summary>
        /// reads only the package id from a sims3pack file
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public string readOnlyPackageIdFromSims3Pack(string filePath)
        {
            int binaryStartPosition = 0;
            string packageId = "";

            string sims3PackXmlPart = Sims3PackBinaryReader.getXMLPart(filePath, out binaryStartPosition);
            if (sims3PackXmlPart != "")
            {
                packageId = readPackageIdXML(sims3PackXmlPart);
            }

            return packageId;
        }

        /// <summary>
        /// only read package id from xml
        /// </summary>
        /// <param name="sims3PackXmlPart"></param>
        /// <returns></returns>
        private string readPackageIdXML(string sims3PackXmlPart)
        {
            string packageId = "";

            try
            {
                XmlDocument xmlDocument = new XmlDocument();
                xmlDocument.LoadXml(sims3PackXmlPart);

                XmlNode root = xmlDocument.DocumentElement;

                foreach (XmlNode sims3packChild in root.ChildNodes)
                {                   
                   if (sims3packChild.Name == xmlStringValues.nodeSims3PackPackageId)
                    {
                        packageId = sims3packChild.InnerText;
                    }
                }
                return packageId;
            }
            catch (Exception)
            {
                throw;
            }
        }
        
        /// <summary>
        /// reads only package id and the english and german display name from a sims3pack file
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="packageId"></param>
        /// <param name="nameDE"></param>
        /// <param name="nameEN"></param>
        public void readPackageIdDisplayNameFromSims3Pack(string filePath, out string packageId, out string nameDE, out string nameEN)
        {
            int binaryStartPosition = 0;
            packageId = "";
            nameDE = "";
            nameEN = "";

            string sims3PackXmlPart = Sims3PackBinaryReader.getXMLPart(filePath, out binaryStartPosition);
            if (sims3PackXmlPart != "")
            {
                readPackageIdDisplayNameXML(sims3PackXmlPart, out packageId, out nameDE, out nameEN);
            }
        }

        /// <summary>
        /// reads only the package id and german and english names from the xml
        /// </summary>
        /// <param name="sims3PackXmlPart"></param>
        /// <param name="packageId"></param>
        /// <param name="nameDE"></param>
        /// <param name="nameEN"></param>
        private void readPackageIdDisplayNameXML(string sims3PackXmlPart, out string packageId, out string nameDE, out string nameEN)
        {
            packageId = "";
            nameDE = "";
            nameEN = "";

            string displayName = "";

            try
            {
                XmlDocument xmlDocument = new XmlDocument();
                xmlDocument.LoadXml(sims3PackXmlPart);

                XmlNode root = xmlDocument.DocumentElement;

                foreach (XmlNode sims3packChild in root.ChildNodes)
                {
                    if (sims3packChild.Name == xmlStringValues.nodeSims3PackPackageId)
                    {
                        packageId = sims3packChild.InnerText;
                    }
                    else if (sims3packChild.Name == xmlStringValues.nodeSims3PackDisplayName)
                    {
                        displayName = sims3packChild.InnerText;
                    }
                    else if (sims3packChild.Name == xmlStringValues.nodeSims3PackLocalizedNames)
                    {
                        readPackageLocaliszedNames(sims3packChild, out nameDE, out nameEN);
                    }
                }
                if (nameDE =="")
                {
                    nameDE = displayName;
                }
                if (nameEN == "")
                {
                    nameEN = displayName;
                }
            }
            catch (Exception)
            {
                throw;
                
            }
        }

        /// <summary>
        /// reads the german and english names from the localized names
        /// </summary>
        /// <param name="root"></param>
        /// <param name="nameDE"></param>
        /// <param name="nameEN"></param>
        private void readPackageLocaliszedNames(XmlNode root, out string nameDE, out string nameEN)
        {
            nameDE = "";
            nameEN = "";

            foreach (XmlNode child in root.ChildNodes)
            {
                if (child.Attributes[0].Value == "en-US")
                {
                    if (child.FirstChild.NodeType == XmlNodeType.CDATA)
                    {
                        nameEN = child.FirstChild.Value;
                    }
                }
                else if (child.Attributes[0].Value == "de-DE")
                {
                    if (child.FirstChild.NodeType == XmlNodeType.CDATA)
                    {
                        nameDE = child.FirstChild.Value;
                    }
                }
                
               
            }
        }
       
        #region decodeXML

        /// <summary>
        /// read the whole xml part of the sims3pack file
        /// </summary>
        /// <param name="stringXml"></param>
        /// <param name="filePath"></param>
        /// <param name="binaryStartPosition"></param>
        /// <returns></returns>
        private ContentDescription readXML(string stringXml, string filePath, int binaryStartPosition)
        {
            try
            {
                XmlDocument xmlDocument = new XmlDocument();
                xmlDocument.LoadXml(stringXml);

                XmlNode root = xmlDocument.DocumentElement;

                ContentDescription contentDescription = new ContentDescription();
                contentDescription.FilePath = filePath;
                contentDescription.BinaryStartPosition = binaryStartPosition;


                XmlAttributeCollection sims3PackAttributes = root.Attributes;


                //get the sims3pack type
                foreach (XmlAttribute attribute in sims3PackAttributes)
                {
                    if (attribute.Name == xmlStringValues.attrrContentType)
                    {
                        contentDescription.Type = ReferenceResolver.StringToContentType(attribute.Value);
                        break;
                    }

                }

                decodeXMLSims3PackNodes(root, contentDescription);
                
                return contentDescription;
            }
            catch(Exception)
            {
                throw;
            }
            
        }
        /// <summary>
        /// reads information from the xml nodes
        /// the content description keeps information common for all types
        /// </summary>
        /// <param name="root">root node Sims3Pack</param>
        /// <param name="contentDescription">ContentDescription object to be filled with information</param>
        private void decodeXMLSims3PackNodes(XmlNode root, ContentDescription contentDescription)
        {
            foreach (XmlNode sims3packChild in root.ChildNodes)
            {

                if (sims3packChild.Name == xmlStringValues.nodeSims3PackGameVersion)
                {
                    contentDescription.GameVersion = sims3packChild.InnerText;
                }
                else if (sims3packChild.Name == xmlStringValues.nodeSims3PackDisplayName)
                {
                    contentDescription.DisplayName = sims3packChild.InnerText;
                }
                else if (sims3packChild.Name == xmlStringValues.nodeSims3PackDescription)
                {
                    contentDescription.Description = sims3packChild.InnerText;
                }
                else if (sims3packChild.Name == xmlStringValues.nodeSims3PackPackageId)
                {
                    contentDescription.PackageID = sims3packChild.InnerText;
                }
                else if (sims3packChild.Name == xmlStringValues.nodeSims3PackDependencies)
                {
                    decodeXmlDependencies(sims3packChild, contentDescription);
                }
                else if (sims3packChild.Name == xmlStringValues.nodeSims3PackPackagedFile)
                {
                    decodeXMLPackagedFile(sims3packChild, contentDescription);
                }
            }
        }

        /// <summary>
        /// resolves the dependencies
        /// information is added to the content description
        /// </summary>
        /// <param name="root">root XmlNode: Dependencies</param>
        /// <param name="contentDescription">ContentDescription object</param>
        private void decodeXmlDependencies(XmlNode root, ContentDescription contentDescription)
        {
           
            foreach (XmlNode dependency in root.ChildNodes)
            {
                string dependencyGuid = dependency.InnerText;
                Dependency contentDependency = null;

                if (this.ReferenceResolver.containsDependencyGuid(dependencyGuid))
                {
                    contentDependency = this.ReferenceResolver.getDependency(dependencyGuid);

                    if (contentDependency != null)
                    {
                        switch (contentDependency.DependencyType)
                        {
                            case DependencyTypes.expansion:
                                DescriptionItem expansion = new DescriptionItem();
                                expansion.DE = contentDependency.NameDE;
                                expansion.EN = contentDependency.NameEN;
                                contentDescription.addExpansion(expansion);
                                break;
                            case DependencyTypes.stuffpack:
                                DescriptionItem stuffpack = new DescriptionItem();
                                stuffpack.DE = contentDependency.NameDE;
                                stuffpack.EN = contentDependency.NameEN;
                                contentDescription.addStuffpack(stuffpack);
                                break;
                            case DependencyTypes.store:
                                DescriptionItem storeitem = new DescriptionItem();
                                storeitem.DE = contentDependency.NameDE;
                                storeitem.EN = contentDependency.NameEN;                                        
                                contentDescription.addStoreItem(storeitem);
                                break;                                    
                            default:
                                break;
                        }
                    }
                    else
                    {
                        throw new Exception("Invalid dependency object");
                    }

                }                      
                        
            }
               
        }
        
        /// <summary>
        /// decodes the packageFile subnodes
        /// </summary>
        /// <param name="root">package file node</param>
        /// <param name="contentDescription"></param>
        private void decodeXMLPackagedFile(XmlNode root, ContentDescription contentDescription)
        {
            PackagedFileDescription packagedFileDescription = new PackagedFileDescription();
            
            foreach (XmlNode packedFileChild in root.ChildNodes)
            {
                if (packedFileChild.Name == xmlStringValues.nodePackagedFileName)
                {
                    packagedFileDescription.Name = packedFileChild.InnerText;
                }
                else if (packedFileChild.Name == xmlStringValues.nodePackagedFileLength)
                {
                    packagedFileDescription.Length = packedFileChild.InnerText;
                }
                else if (packedFileChild.Name == xmlStringValues.nodePackagedFileOffset)
                {
                    packagedFileDescription.Offset = packedFileChild.InnerText;
                }
                else if (packedFileChild.Name == xmlStringValues.nodePackagedFileGuid)
                {
                    packagedFileDescription.Guid = packedFileChild.InnerText;
                }
                else if (packedFileChild.Name == xmlStringValues.nodePackagedFileContentType)
                {
                    packagedFileDescription.ContentType = ReferenceResolver.StringToContentType(packedFileChild.InnerText);
                }
                else if (packedFileChild.Name == xmlStringValues.nodePackagedFileThumbnail)
                {
                    packagedFileDescription.IsThumbnail = true;
                }
                else if (packedFileChild.Name == xmlStringValues.nodePackagedFileMetatags)
                {
                    // presumes that metagtas is the last subnode                    
                    // the next steps depend form the already decoded information
                    // a) isThumbnail is false and PackagedFile Guid and ContenDescription PackageId are the same
                    //      a) 1.) and ContentType is supported -> decode metatags
                    //      a) 2.) and ContentType is not supported -> metatags are not decoded
                    // b) isThumbnail is false and PackagedFile Guid and ContenDescription PackageId aren't the same
                    //     -> add package to the list of the the main package packed files
                    // c) isThumbnail is true -> create bitmap object from png file and add it to the bitmap list (thumbnails have no meta information)
                    
                    //packed file is no thumbnail
                    if (!packagedFileDescription.IsThumbnail)
                    {
                        //packed file is main package
                        if (packagedFileDescription.Guid == contentDescription.PackageID)
                        {
                            switch (packagedFileDescription.ContentType)
                            {
                                case ContentTypes.sim:
                                    PackagedSimDescription simDescription = new PackagedSimDescription(packagedFileDescription);
                                    contentDescription.PackagedMainFile = simDescription;                                   
                                    decodeXMLMetaSim(packedFileChild, contentDescription.PackagedMainFile as PackagedSimDescription);
                                    break;
                                case ContentTypes.lot:
                                    PackagedLotDescription lotDescription = new PackagedLotDescription(packagedFileDescription);
                                    contentDescription.PackagedMainFile = lotDescription;
                                    decodeXMLMetaLot(packedFileChild, contentDescription.PackagedMainFile as PackagedLotDescription);
                                    break;
                                case ContentTypes.household:
                                    PackagedHouseholdDescription householdDescription = new PackagedHouseholdDescription(packagedFileDescription);
                                    contentDescription.PackagedMainFile = householdDescription;
                                    decodeXMLMetaHousehold(packedFileChild, contentDescription.PackagedMainFile as PackagedHouseholdDescription);                                   
                                    break;
                                case ContentTypes.world:
                                    PackagedWorldDescription worldDescription = new PackagedWorldDescription(packagedFileDescription);
                                    contentDescription.PackagedMainFile = worldDescription;
                                    decodeXMLMetaWorld(packedFileChild, contentDescription.PackagedMainFile as PackagedWorldDescription);                                   
                                    break;
                                case ContentTypes.preset:
                                    PackagedPresetDescription presetDescription = new PackagedPresetDescription(packagedFileDescription);
                                    contentDescription.PackagedMainFile = presetDescription;
                                    decodeXMLMetaPreset(packedFileChild, contentDescription.PackagedMainFile as PackagedPresetDescription); 
                                    break;
                                case ContentTypes.haircolorinfo:
                                case ContentTypes.CASPart:
                                case ContentTypes.gameobject:
                                    contentDescription.PackagedMainFile = packagedFileDescription;
                                    break;
                                case ContentTypes.coatset:
                                    PackagedCoatsetDescription coatsetDescription = new PackagedCoatsetDescription(packagedFileDescription);
                                    contentDescription.PackagedMainFile = coatsetDescription;
                                    decodeXMLMetaCoatset(packedFileChild, contentDescription.PackagedMainFile as PackagedCoatsetDescription); 
                                    break;
                                case ContentTypes.pattern:
                                case ContentTypes.cascolorinfo:
                                    PackagedPatternDescription patternDescription = new PackagedPatternDescription(packagedFileDescription);
                                    contentDescription.PackagedMainFile = patternDescription;
                                    decodeXMLMetaPattern(packedFileChild, contentDescription.PackagedMainFile as PackagedPatternDescription); 
                                    break;
                                default:
                                    //when type is not supported only common information is read in
                                    contentDescription.PackagedMainFile = packagedFileDescription;
                                    break;
                            }
                        }
                        //packed file is not main package
                        else
                        {
                            bool isBadCC = this.ReferenceResolver.containsBadCCGuid(packagedFileDescription.Guid);
                            bool isKnownPackage = this.ReferenceResolver.containsKnownPackageGuid(packagedFileDescription.Guid);

                            if (isBadCC || isKnownPackage)
                            {
                                //check if bad cc -> add to bad cc list
                                if (isBadCC)
                                {
                                    PackagedBadCCDescription badCCDescription = new PackagedBadCCDescription(packagedFileDescription);

                                    //get additional information
                                    BadCC badCCInfo = this.ReferenceResolver.getBadCC(packagedFileDescription.Guid);
                                    badCCDescription.InfoFileName = badCCInfo.Name;
                                    badCCDescription.BadCCType = badCCInfo.Type;

                                    contentDescription.addBadCCPackedFile(badCCDescription);
                                }
                                //check if known package -> add to known package list
                                if (isKnownPackage)
                                {                                    
                                    PackagedKnownFileDescription knownPackDescription = new PackagedKnownFileDescription(packagedFileDescription);

                                    //get additional information
                                    KnownPackage knownPackage = this.ReferenceResolver.getKnownPackage(packagedFileDescription.Guid);
                                    knownPackDescription.ItemNameDE = knownPackage.ItemNameDE;
                                    knownPackDescription.ItemNameEN = knownPackage.ItemNameEN;
                                    knownPackDescription.Creator = knownPackage.Creator;
                                    knownPackDescription.Homepage = knownPackage.Homepage;

                                    contentDescription.addPackedFile(knownPackDescription);
                                }
                            }
                            else
                            {
                                contentDescription.addUnknownPackedFile(packagedFileDescription);
                            }

                        }
                    }
                    //packed file is Thumbnail
                    else
                    {                        
                        int offset = toInt(packagedFileDescription.Offset);
                        int length = toInt(packagedFileDescription.Length);

                        Bitmap thumbnail = Sims3PackBinaryReader.getThumbnail(contentDescription.FilePath, offset, length, contentDescription.BinaryStartPosition);

                        if (thumbnail != null)
                        {
                            contentDescription.addThumbnail(thumbnail);
                        }
                        
                    }
                }
            }
                          
        }

        /// <summary>
        /// decodes pattern specific xml information
        /// </summary>
        /// <param name="root"></param>
        /// <param name="description"></param>
        private void decodeXMLMetaPattern(XmlNode root, PackagedPatternDescription description)
        {
            foreach (XmlNode metatagChild in root.ChildNodes)
            {
                if (metatagChild.Name == xmlStringValues.nodeMetaMatCategory)
                {
                    description.MatCategory.DE = ReferenceResolver.resolveMatCategory(metatagChild.InnerText, Languages.de);
                    description.MatCategory.EN = ReferenceResolver.resolveMatCategory(metatagChild.InnerText, Languages.en);
                }
            }
        }

        /// <summary>
        /// decodes coatset specific information
        /// </summary>
        /// <param name="root"></param>
        /// <param name="description"></param>
        private void decodeXMLMetaCoatset(XmlNode root, PackagedCoatsetDescription description)
        {
            foreach (XmlNode metatagChild in root.ChildNodes)
            {
                if (metatagChild.Name == xmlStringValues.nodeMetaCoatsetAge)
                {
                    description.Age.DE = this.ReferenceResolver.resolveAge(metatagChild.InnerText, Languages.de);
                    description.Age.EN = this.ReferenceResolver.resolveAge(metatagChild.InnerText, Languages.en);
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaCoatsetSpecies)
                {
                    description.Species.DE = this.ReferenceResolver.resolveSpecies(metatagChild.InnerText, Languages.de);                    
                    description.Species.EN = this.ReferenceResolver.resolveSpecies(metatagChild.InnerText, Languages.en);
                }  
            }
        }

        /// <summary>
        /// decodes preset specific information
        /// </summary>
        /// <param name="root"></param>
        /// <param name="description"></param>
        private void decodeXMLMetaPreset(XmlNode root, PackagedPresetDescription description)
        {
            foreach (XmlNode metatagChild in root.ChildNodes)
            {
                if (metatagChild.Name == xmlStringValues.nodeMetaPresetAgeGenderFlags)
                {
                    description.AgeGenderFlags = metatagChild.InnerText;
                    string ageList, genderList;
                    ReferenceResolver.resolveAgeGenderFlags(metatagChild.InnerText, Languages.de, out genderList, out ageList);
                    description.Age.DE = ageList;
                    description.Gender.DE = genderList;

                    ReferenceResolver.resolveAgeGenderFlags(metatagChild.InnerText, Languages.en, out genderList, out ageList);
                    description.Age.EN = ageList;
                    description.Gender.EN = genderList;
                }
            }
        }

        /// <summary>
        /// decode world specific information
        /// </summary>
        /// <param name="root"></param>
        /// <param name="description"></param>
        private void decodeXMLMetaWorld(XmlNode root, PackagedWorldDescription description)
        {
            foreach (XmlNode metatagChild in root.ChildNodes)
            {
                if (metatagChild.Name == xmlStringValues.nodeMetaWorldName)
                {
                    description.MetaName = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaWorldDescription)
                {
                    description.MetaDescription = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaWorldNoLots)
                {
                    description.WorldNoLots = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaWorldNumResLots)
                {
                    description.WorldNumResidentialLots = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaWorldNumComLots)
                {
                    description.WorldNumCommercialLots = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaWorldNumOccLots)
                {
                    description.WorldNumOccupiedLots = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaWorldNumSims)
                {
                    description.WorldNumSims = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaWorldDimX)
                {
                    description.DimX = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaWorldDimZ)
                {
                    description.DimZ = metatagChild.InnerText;
                }

            }
        }      
   
        /// <summary>
        /// decode household specific information
        /// </summary>
        /// <param name="root"></param>
        /// <param name="description"></param>
        private void decodeXMLMetaHousehold(XmlNode root, PackagedHouseholdDescription description)
        {
            foreach (XmlNode metatagChild in root.ChildNodes)
            {
                if (metatagChild.Name == xmlStringValues.nodeMetaHouseholdName)
                {
                    description.MetaName = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaHouseholdNumOfThumbs)
                {
                    description.NumOfThumbs = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaHouseholdHouseholdName)
                {
                    description.HouseholdName = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaHouseholdFunds)
                {
                    description.Funds = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaHouseholdSims)
                {
                    decodeXMLSims(metatagChild, description);
                }
                
            }
        }
       
        /// <summary>
       /// decodes a sims section
       /// is part of housholds and occupied lots
       /// </summary>
       /// <param name="root"></param>
       /// <param name="description"></param>
        private void decodeXMLSims(XmlNode root, IPackagedSimGroupDescription description)
        {
            foreach (XmlNode simsChild in root.ChildNodes)
            {
                description.addSimDescription(decodeXMLSim(simsChild));
            }
        }

        /// <summary>
        /// decodes a sim description contained in a sims section (housholds, occupied lots)
        /// </summary>
        /// <param name="root"></param>
        /// <returns></returns>
        private SimpleSimDescription decodeXMLSim(XmlNode root)
        {
            SimpleSimDescription simDescription = new SimpleSimDescription();
            
            foreach (XmlNode simChild in root.ChildNodes)            
            {

                if (simChild.Name == xmlStringValues.nodeMetaSimsSectionName)
                {
                    simDescription.Name = simChild.InnerText;
                }
                else if (simChild.Name == xmlStringValues.nodeMetaSimsSectionBio)
                {
                    simDescription.Bio = simChild.InnerText;
                }
                else if (simChild.Name == xmlStringValues.nodeMetaSimsSectionAge)
                {
                    simDescription.Age.DE = this.ReferenceResolver.resolveAge(simChild.InnerText, Languages.de);
                    simDescription.Age.EN = this.ReferenceResolver.resolveAge(simChild.InnerText, Languages.en);
                }
                else if (simChild.Name == xmlStringValues.nodeMetaSimsSectionSpecies)
                {
                    SimTypes type;
                    simDescription.Species.DE = this.ReferenceResolver.resolveSpeciesAndGetSimType(simChild.InnerText, Languages.de, out type);
                    simDescription.SimType = type;
                    simDescription.Species.EN = this.ReferenceResolver.resolveSpecies(simChild.InnerText, Languages.en);
                }
                else if (simChild.Name == xmlStringValues.nodeMetaSimsSectionGender)
                {
                    simDescription.Gender.DE = this.ReferenceResolver.resolveGender(simChild.InnerText, Languages.de);
                    simDescription.Gender.EN = this.ReferenceResolver.resolveGender(simChild.InnerText, Languages.en);
                }                

            }
            return simDescription;
        }

        /// <summary>
        /// decode lot specific information
        /// </summary>
        /// <param name="root"></param>
        /// <param name="description"></param>
        private void decodeXMLMetaLot(XmlNode root, PackagedLotDescription description)
        {
            foreach (XmlNode metatagChild in root.ChildNodes)
            {
                if (metatagChild.Name == xmlStringValues.nodeMetaLotName)
                {
                    description.MetaName = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaLotDescription)
                {
                    description.MetaDescription = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaLotBio)
                {
                    description.Bio = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaLotNumOfThumbs)
                {
                    description.NumOfThumbs = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaLotMaxLevel)
                {
                    description.MaxLevel = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaLotMinLevel)
                {
                    description.MinLevel = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaLotDimX)
                {
                    description.DimX = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaLotDimZ)
                {
                    description.DimZ = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaLotOccupied)
                {
                    description.IsOccupied = true;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaLotType)
                {
                    if (metatagChild.InnerText == xmlStringValues.nodeMetaLotTypeComLotVal)
                    {
                        description.IsCommunityLot = true;
                    }
                    description.LotType.DE = this.ReferenceResolver.resolveLotType(metatagChild.InnerText, Languages.de);
                    description.LotType.EN = this.ReferenceResolver.resolveLotType(metatagChild.InnerText, Languages.en);
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaLotResSubType)
                {
                    description.LotResSubType.DE = this.ReferenceResolver.resolveLotResSubType(metatagChild.InnerText, Languages.de);
                    description.LotResSubType.EN = this.ReferenceResolver.resolveLotResSubType(metatagChild.InnerText, Languages.en);
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaLotComSubType)
                {
                    description.LotComSubType.DE = this.ReferenceResolver.resolveLotComSubType(metatagChild.InnerText, Languages.de);
                    description.LotComSubType.EN = this.ReferenceResolver.resolveLotComSubType(metatagChild.InnerText, Languages.en);
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaLotHouseholdName)
                {
                    description.LotHouseholdName = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaLotFunds)
                {
                    description.Funds = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaLotSims)
                {
                    decodeXMLSims(metatagChild, description);
                }
            }
        }

        /// <summary>
        /// decodes sim specific information
        /// </summary>
        /// <param name="root"></param>
        /// <param name="description"></param>
        private void decodeXMLMetaSim(XmlNode root, PackagedSimDescription description)
        {
            foreach (XmlNode metatagChild in root.ChildNodes)
            {
                if (metatagChild.Name == xmlStringValues.nodeMetaSimName)
                {
                    description.MetaName = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaSimDescription)
                {
                    description.MetaDescription = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaSimBio)
                {
                    description.Bio = metatagChild.InnerText;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaSimAge)
                {
                    description.Age.DE = this.ReferenceResolver.resolveAge(metatagChild.InnerText, Languages.de);
                    description.Age.EN = this.ReferenceResolver.resolveAge(metatagChild.InnerText, Languages.en);
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaSimGender)
                {
                    description.Gender.DE = this.ReferenceResolver.resolveGender(metatagChild.InnerText, Languages.de);
                    description.Gender.EN = this.ReferenceResolver.resolveGender(metatagChild.InnerText, Languages.en);
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaSimSpecies)
                {
                    SimTypes type;
                    description.Species.DE = this.ReferenceResolver.resolveSpeciesAndGetSimType(metatagChild.InnerText, Languages.de, out type);
                    description.SimType = type;
                    description.Species.EN = this.ReferenceResolver.resolveSpecies(metatagChild.InnerText, Languages.en);
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaSimTraits)
                {
                    decodeXMLTraits(metatagChild, description);
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaSimFavColor)
                {
                    description.FavColor.DE = this.ReferenceResolver.resolveFavColor(metatagChild.InnerText, Languages.de);
                    description.FavColor.EN = this.ReferenceResolver.resolveFavColor(metatagChild.InnerText, Languages.en);
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaSimFavMusic)
                {
                    description.FavMusic.DE = this.ReferenceResolver.resolveFavMusic(metatagChild.InnerText, Languages.de);
                    description.FavMusic.EN = this.ReferenceResolver.resolveFavMusic(metatagChild.InnerText, Languages.en);
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaSimFavFood)
                {
                    description.FavFood.DE = this.ReferenceResolver.resolveFavFood(metatagChild.InnerText, Languages.de);
                    description.FavFood.EN = this.ReferenceResolver.resolveFavFood(metatagChild.InnerText, Languages.en);
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaSimIsVampire)
                {
                    description.IsVampire = true;
                }
                else if (metatagChild.Name == xmlStringValues.nodeMetaSimIsUnicorn)
                {
                    description.IsUnicorn = true;
                }
            }
        }

        /// <summary>
        /// decodes sim traits
        /// </summary>
        /// <param name="root"></param>
        /// <param name="description"></param>
        private void decodeXMLTraits(XmlNode root, PackagedSimDescription description)
        {
            foreach (XmlNode traitsChild in root.ChildNodes)
            {
                DescriptionItem trait = new DescriptionItem();
                trait.DE = this.ReferenceResolver.resolveTrait(traitsChild.InnerText, Languages.de);
                trait.EN = this.ReferenceResolver.resolveTrait(traitsChild.InnerText, Languages.en);
                description.addTrait(trait);
            }
        }

        #endregion

        /// <summary>
        /// converts string to int
        /// </summary>
        /// <param name="xmlValue"></param>
        /// <returns></returns>
        private int toInt(string xmlValue)
        {
            int numVal = 0;

            // ToInt32 can throw FormatException or OverflowException.
            try
            {
                numVal = Convert.ToInt32(xmlValue);
            }
            catch (FormatException)
            {
                Console.WriteLine("Input string is not a sequence of digits.");
            }
            catch (OverflowException)
            {
                Console.WriteLine("The number cannot fit in an Int32.");
            }
            finally
            {
                if (numVal < Int32.MaxValue)
                {
                    Console.WriteLine("The new value is {0}", numVal + 1);
                }
                else
                {
                    Console.WriteLine("numVal cannot be incremented beyond its current value");
                }
            }

            return numVal;
        }

        #endregion
    }
}
